package com.xiguanlezz.cn.consumer.proxy;

import com.xiguanlezz.cn.consumer.Consumer;
import com.xiguanlezz.cn.consumer.context.RpcContext;
import com.xiguanlezz.cn.consumer.future.RpcFuture;
import com.xiguanlezz.cn.protocol.RpcHeadFactory;
import com.xiguanlezz.cn.protocol.RpcProtocol;
import com.xiguanlezz.cn.protocol.RpcRequest;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Author：习惯了种种
 * @CreateDate：2024/11/9 00:25
 * @Description：服务消费者动态代理实现类
 */
public class ObjectProxy<T> implements InvocationHandler {
    private Class<T> interfaceClazz;
    private String serviceVersion;
    private String serviceGroup;
    private long invokeTimeout = 5000L;
    private String serializerType;
    private String invokeMethodType;
    private Consumer consumer;

    public ObjectProxy(Class<T> interfaceClazz, String serviceVersion, String serviceGroup, long invokeTimeout, String serializerType, String invokeMethodType, Consumer consumer) {
        this.interfaceClazz = interfaceClazz;
        this.serviceVersion = serviceVersion;
        this.serviceGroup = serviceGroup;
        this.invokeTimeout = invokeTimeout;
        this.serializerType = serializerType;
        this.invokeMethodType = invokeMethodType;
        this.consumer = consumer;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 请求参数构造
        RpcProtocol<RpcRequest> rpcProtocol = new RpcProtocol<>(
                RpcHeadFactory.createRequestHeader(this.serializerType),
                RpcRequest.builder()
                        .className(method.getDeclaringClass().getName())
                        .methodName(method.getName())
                        .paramTypes(method.getParameterTypes())
                        .params(args)
                        .version(this.serviceVersion)
                        .group(this.serviceGroup)
                        .invokeMethodType(this.invokeMethodType)
                        .build());

        // 服务消费者动态代理的异步调用只需要在这里简单干预下
        if ("async".equals(invokeMethodType)) {
            // 如果是异步调用需要往上下文中塞入Future对象
            RpcFuture rpcFuture = RpcFuture.createRpcFuture(rpcProtocol);
            RpcContext.getContext().setRpcFuture(rpcFuture);
        }

        // 委托给consumer完成远程方法调用
        RpcFuture rpcFuture = this.consumer.sendRequest(rpcProtocol);

        if ("async".equals(invokeMethodType)) {
            return null;
        }

        if (Objects.isNull(rpcFuture)) {
            return null;
        } else {
            return invokeTimeout > 0 ? rpcFuture.get(invokeTimeout, TimeUnit.MILLISECONDS) : rpcFuture.get();
        }
    }
}
